/*
 * Kinetis porting
 * 
 * Author: Major Lin
 * 
*/

#include "grbl.h"
#include "fsl_lpuart.h"
#include "fsl_flash.h"


void sei(){};
void cli(){};
void _delay_ms(int len){};
void _delay_us(int len){};
void arch_spindle_tpm_init(){};
uint8_t arch_spindle_tpm_status(){};
void arch_spindle_tpm_update_pwm(){};

void arch_stepper_init(){
  PCC_LPIT0 |= (PCC_CLKCFG_CGC_MASK|PCC_CLKCFG_PCS(3));
  // reset
  LPIT0->MCR |= LPIT_MCR_SW_RST_MASK;
  LPIT0->MCR &= ~LPIT_MCR_SW_RST_MASK;
  LPIT0->MCR |= LPIT_MCR_M_CEN_MASK;
  for (int i=0; i< 100; i++){asm("NOP");}
  // setup channel
  LPIT0->CHANNEL[0].TCTRL = 0;
  LPIT0->CHANNEL[0].TVAL = 48000000;
  // enable irq
  LPIT0->MIER |= 1;
  EnableIRQ(LPIT0_IRQn);
  // start timer
  LPIT0->SETTEN |= LPIT_SETTEN_SET_T_EN_0_MASK;
}
void arch_compare_match_isr_enable(){
  LPIT0->MIER |= 1;
  //EnableIRQ(LPIT0_IRQn);
}
void arch_compare_match_isr_disable(){
  //DisableIRQ(LPIT0_IRQn);
  LPIT0->MIER =0;
}
void arch_timer_reset(){
}

void arch_update_step_timer_start(uint32_t val){
//  LPIT0->MSR |= 1;
  LPIT0->CHANNEL[0].TVAL = val*1024;
}

uint32_t lut[]={0x01, 0x05, 0x04, 0x06, 0x02, 0x0a, 0x08, 0x09};
void arch_step_ouput(uint32_t step_outbits, uint32_t dir_outbits){
  static int x_index=0;
  static int y_index=0;
  if(step_outbits&(1<<X_STEP_BIT)){
    if(dir_outbits&(1<<X_DIRECTION_BIT)){
      x_index++;
    }else{
      x_index--;
    }
    if(x_index==8){x_index=0;}
    if(x_index==-1){x_index=7;}
    GPIOC->PDOR = lut[x_index] << 9;
  }
  if(step_outbits&(1<<Y_STEP_BIT)){
    // Y move
    if(dir_outbits&(1<<Y_DIRECTION_BIT)){
      y_index++;
    }else{
      y_index--;
    }
    if(y_index==8){y_index=0;}
    if(y_index==-1){y_index=7;}
    GPIOA->PDOR = ((lut[y_index]&0x03)|((lut[y_index]&0x0c)<<1)|0x04) << 17;
  }
}

void arch_serial_init(){
  lpuart_config_t user_config;
  CLOCK_SetIpSrc(kCLOCK_Lpuart0, kCLOCK_IpSrcFircAsync);

  uint32_t uartClkSrcFreq = CLOCK_GetIpFreq(kCLOCK_Lpuart0);
  LPUART_GetDefaultConfig(&user_config);
  user_config.baudRate_Bps = BAUD_RATE;
  LPUART_Init(BOARD_DEBUG_UART_BASEADDR, &user_config, uartClkSrcFreq);
  LPUART0->CTRL |= (LPUART_CTRL_TE_MASK|LPUART_CTRL_RE_MASK);
  BOARD_DEBUG_UART_BASEADDR->CTRL |= LPUART_CTRL_TIE_MASK;
  BOARD_DEBUG_UART_BASEADDR->CTRL |= LPUART_CTRL_RIE_MASK;
 // BOARD_DEBUG_UART_BASEADDR->FIFO &= ~(LPUART_FIFO_TXFE_MASK|LPUART_FIFO_RXFE_MASK);
  BOARD_DEBUG_UART_BASEADDR->FIFO &= ~(LPUART_FIFO_RXIDEN_MASK);
  BOARD_DEBUG_UART_BASEADDR->FIFO &= ~(LPUART_FIFO_TXOFE_MASK|LPUART_FIFO_RXUFE_MASK);
  BOARD_DEBUG_UART_BASEADDR->FIFO |= ~(LPUART_FIFO_RXIDEN(1));
  EnableIRQ(LPUART0_IRQn);
}
void arch_serial_tx_empty_isr_enable(){
  BOARD_DEBUG_UART_BASEADDR->CTRL |= LPUART_CTRL_TIE_MASK;
}
void arch_serial_tx_empty_isr_disable(){
  BOARD_DEBUG_UART_BASEADDR->CTRL &= ~LPUART_CTRL_TIE_MASK;
}
void arch_serial_write_byte(unsigned char data){
    LPUART_WriteByte(BOARD_DEBUG_UART_BASEADDR, data);
};
/* arch serial read*/
unsigned char arch_serial_read_byte(){
    return LPUART_ReadByte(BOARD_DEBUG_UART_BASEADDR);
}
void LPUART0_IRQHandler(){
  if (LPUART0->STAT & LPUART_STAT_RDRF_MASK){
    LPUART0->STAT |= LPUART_STAT_RDRF_MASK; // clear status
    arch_serial_rx_isr();
    return;
  }
  if (LPUART0->STAT & LPUART_STAT_TDRE_MASK){
    LPUART0->STAT |= LPUART_STAT_TDRE_MASK; // clear status
    arch_serial_tx_isr();
    return;
  }
  //while(1); // should never be here
}

void arch_flash_program(uint32_t address, char *data, uint32_t len){
    static flash_config_t s_flashDriver;
    memset(&s_flashDriver, 0, sizeof(flash_config_t));
    CLOCK_EnableClock(kCLOCK_Mscm);
    uint32_t alien_len = (len&0xfffffff0);
    if (alien_len != len){alien_len += 0x10;}
    FLASH_Init(&s_flashDriver);
    FLASH_Erase(&s_flashDriver, address, alien_len, kFLASH_ApiEraseKey);
    FLASH_Program(&s_flashDriver, address, data, alien_len);
}